/*
 * ============================================================================
 *                   GNU Lesser General Public License
 * ============================================================================
 *
 *
 *
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
 * 
 *
 *
 */
package rad.framework.security;

import java.lang.reflect.Field;
import java.security.Principal;

import javax.annotation.Resource;
import javax.ejb.SessionContext;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
import javax.persistence.EntityManager;

import rad.framework.jpa.HibernateUtil;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Session;
import org.hibernate.ejb.HibernateEntityManager;
import org.jboss.ejb3.entity.HibernateSession;

/**
 * This interceptor enables the currentUser filter with the name of the caller
 * principal.
 * 
 * Example filter definition on a Payment entity with an association to a
 * Customer entity:
 * 
 * @FilterDef(name = "currentUser", parameters = {
 * @ParamDef(name = "currentUser", type = "string") })
 * @Filter(name = "currentUser", condition = "customer1_.name = :currentUser")
 * 
 * @author boudyacho
 * 
 */
public class CurrentUserFilter {

	private static final Log logger = LogFactory
			.getLog(CurrentUserFilter.class);

	@Resource
	private SessionContext sessionCtx;

	/**
	 * @param ctx
	 * @return
	 * @throws Exception
	 */
	@AroundInvoke
	public Object invoke(InvocationContext ctx) throws Exception {
		Principal currentUser = sessionCtx.getCallerPrincipal();
		if (currentUser != null) {
			String name = currentUser.getName();
			logger.debug("Current User: " + name);

			EntityManager em = getManager(ctx);
			Session session = HibernateUtil.getSession(em);
			session.enableFilter("currentUser").setParameter("currentUser",
					name);
		} else {
			logger.error("No Current User. Filter is not enabled!");
		}
		return ctx.proceed();
	}

	/**
	 * @param ctx
	 * @return
	 * @throws Exception
	 */
	private EntityManager getManager(InvocationContext ctx) throws Exception {
		// TODO change this to access the mgr via accessor method
		Field[] fields = getFields(ctx.getTarget().getClass());
		for (Field field : fields) {
			if (field.getType().equals(EntityManager.class)) {
				return (EntityManager) field.get(ctx.getTarget());
			}
		}
		throw new RuntimeException(ctx.getTarget() + " has no entity manager");
	}

	private Field[] getFields(Class clazz) {
		Field[] fields = clazz.getDeclaredFields();
		// Field[] sfields = getFields(clazz.getSuperclass());
		return fields;
	}

}